#include <SPI.h>
#include <Ethernet.h>


//===========================================
// BOARD_TYPE: UNO
// SKETCH_NAME: BESS
//======================================
// Important information
//
// Note:
// Arduino communicates with both the W5100 and SD card using the SPI bus (through the ICSP header).
// This is on D11, D12, and D13 on "classic" format Arduino models such as the Duemilanove, 
// and pins D50, D51, and D52 on the Arduino Mega.
// D10 is used to select the W5100 and cannot be used for general I/O.
// D4 is used for the SD card and can only be used for general I/O if the SD slot is not occupied.
// D2 is used if a solder bridge is placed across the "INT" pads to connect it to the W5100's INT pin.
//======================================
//   1000 imp/kwh M?taren
//   1 impuls = 1 wh  ->  3600/deltaTid(s) kW energif?rbrukning
//======================================
// Revision History
// 2012-09-14
// 2013-01-04
//

//======================================
// User Configurations
//======================================
//const int BESS_ERR    = 9; // Orange wire
const int BESS_COM    = 8; // White wire
//const int BESS_MSG    = 7; // Blue wire
const int BESS_NET    = 4; // Green wire
const int BESS_SIG    = 7; // Yellow wire
const int BESS_POW_VU = 6; // PWM Power analog-meter
const int BESS_SIG_VU = 9; // PWM Signal analog-meter
const int intPin      = 2;  // the interrupt pin

const int adactive    = 3;  // Analog Pin Signal
const int tempSensor  = 2;  // Temeperature Sensor
const int LED_NO_ETH_CONNECTION    = 3;
const int LED_NO_SERVER_CONNECTION = 6;
const int LED_MAX_POWER            = 2;
const int LED_STARTUP              = 1;


// BESS  StateMachine
const int RUNNING        = 1;
const int ETH_ERROR      = 2;
const int SERVER_ERROR   = 3;
const int NO_BYTES_ERROR = 4;
//======================================
// User Configurations
//======================================
int user   = 1;    // 1 = Kyrkvardsvagen 32
int implev = 10;   // Threshold for detecting impuls
int loglev = 1;    // Detailed logging on/off  1/0
//======================================
// Global Declarations
//======================================
int bess_status = 0;
int i,nBytes=0;
char c,sconf[800];

int TRIGLEVEL = 40;       // triglevel on analog signal 1023 = 5.0V
int UNTRIGLEVEL = 30;

#define KWHC (3600000L)    // pwr at one pulse per ms, i.e. 1000 pulses per kwh.

struct intdata {
  /* internal data */
  volatile int base;
  volatile int baserem;
  volatile int sig;
  volatile int sigrem;
  volatile int trig;
  volatile long prevtime;
  volatile int pulses;
  /* external data for background prog */
  volatile int ptrig;
  volatile int ppulses;
  volatile long powertime;
  volatile long power; 
  volatile int sigmax;
} id1;

volatile long adint = 0;

int temp;

void iniid(struct intdata *id)
{
  id->base = 0;
  id->sig  = 0;
  id->trig = 0;
  id->prevtime = 0;
  id->pulses = 0;
}

//======================================

byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
char serverName[] = "bess.simuino.com";
EthernetClient client;

//======================================
void blink(int led,int n, int freq)
//======================================
{
  int i;
  digitalWrite(led,LOW);
  delay(freq);
  for(i=0;i<n;i++)
    {
      digitalWrite(led,HIGH);
      delay(freq);
      digitalWrite(led,LOW);
      delay(freq);
    }
}
//======================================
void puls(int led,int n, int freq)
//======================================
{
  int i;
  digitalWrite(led,LOW);
  for(i=0;i<n;i++)
    {
      digitalWrite(led,HIGH);
      delay(2);
      digitalWrite(led,LOW);
      delay(freq);
    }
}
//======================================
int getValue(char *s, char q[40])
//======================================
{
  char *p;
  int res = 0;
  if(p=strstr(s,q))
    {
      p=strstr(p,"=");
      p++;
      //Serial.println(p);
      sscanf(p,"%d",&res);
    }
  return(res);
}

//======================================
void adpoll()
//======================================
{ 
  int ad1;
  int tmp, stmp;
  long tmpl;
    
  adint++;
    
  ad1 = analogRead(adactive);
  //analogWrite(BESS_SIG_VU, ad1 / 4); 

  // filter base, tau = 0.256 seconds.
  tmp = (ad1 - id1.base + id1.baserem) & 0xff;
  id1.base = id1.base + ((ad1 - id1.base + id1.baserem) >> 8);
  id1.baserem = tmp;
    
  // filter sig, tau = 0.004 seconds.
  stmp = ad1 - id1.base;
  tmp = (stmp - id1.sig + id1.sigrem) & 0x03;
  id1.sig = id1.sig + ((stmp - id1.sig + id1.sigrem) >> 2);
  id1.sigrem = tmp;
    
  if (id1.sig > id1.sigmax) id1.sigmax = id1.sig;
    
  if ((id1.trig) && (id1.sig < UNTRIGLEVEL)) 
    {
      id1.trig = 0;
      digitalWrite(BESS_SIG, 0);
    }
    
  if ((id1.trig == 0) && (id1.sig >= TRIGLEVEL)) 
    {
      id1.trig = 1;  // we found a pulse
      digitalWrite(BESS_SIG, 1);  // mirror input to output  
      id1.pulses++;
      if (id1.sig > id1.sigmax) id1.sigmax = id1.sig;
      tmpl = adint - id1.prevtime;
      if (tmpl >= 10000) // more than 10 seconds? 
	{       
	  id1.power =  id1.pulses * KWHC / tmpl;
	  id1.powertime = tmpl;
	  id1.prevtime = adint;
	  id1.ppulses = id1.pulses;
	  id1.pulses = 0;
	  id1.ptrig = 1;          
	}
    }
}


//======================================
void setup()
//======================================
{
  // pinMode(BESS_ERR,   OUTPUT);
  pinMode(BESS_COM,   OUTPUT);
  //pinMode(BESS_MSG,   OUTPUT);
  pinMode(BESS_SIG,   OUTPUT);
  pinMode(BESS_NET,   OUTPUT);  
  pinMode(BESS_POW_VU,OUTPUT);
  pinMode(BESS_SIG_VU,OUTPUT);
  pinMode(BESS_NET,   OUTPUT);  
  pinMode(intPin,     OUTPUT);
  
  Serial.begin(9600);
  
  blink(BESS_COM,2,200);
  blink(BESS_NET,2,200);
  blink(BESS_SIG,2,200);
  
  adint = 0;
  iniid(&id1);

  attachInterrupt(0, adpoll, FALLING);
  bess_status = RUNNING;
  
  // Test calibration of VU meter    
    analogWrite(BESS_SIG_VU,127);
    delay(2000);
    analogWrite(BESS_SIG_VU,0);
    delay(2000);
    analogWrite(BESS_SIG_VU,255);
    delay(2000);
    analogWrite(BESS_SIG_VU,127);
    
  
  // start the Ethernet connection:
  digitalWrite(BESS_COM,HIGH);
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    bess_status = ETH_ERROR;
    digitalWrite(BESS_COM,LOW);
  }
  // give the Ethernet shield a second to initialize:
  if(bess_status == RUNNING);
  {
     digitalWrite(BESS_NET,HIGH);
     digitalWrite(BESS_COM,LOW);
     delay(1000);

     Serial.println(" connecting user...");
     Serial.print(user);
     

     if (client.connect(serverName, 80)) 
     {
        Serial.println("Connected to BESS server...");
       //client.print("GET /bess/data.php?conf=");
        client.print("GET /data.php?conf=");
        client.print(user);
        client.println(" HTTP/1.1");
        client.println("Host: bess.simuino.com");
       //client.println("Host: 127.0.0.1");
        client.println(); 
        

    } 
    else 
    {
      digitalWrite(BESS_COM,LOW);
      Serial.println("Connection to BESS server failed...");
      bess_status = SERVER_ERROR;
    }
  }  
  
  if(bess_status == RUNNING);
  {
    delay(3000);  // Give time to receive answer from BESS Server
    // Get number of bytes in answer from server
    nBytes = client.available();
    digitalWrite(BESS_SIG,HIGH);
    digitalWrite(BESS_NET,LOW);
    Serial.print("Bytes from server: ");
    Serial.println(nBytes);
    if(nBytes==0)bess_status = NO_BYTES_ERROR;
  
    // Show answer from server
    if (nBytes > 0) 
    {
      for(i=0;i<nBytes;i++)
	{
	  c = client.read();
	  sconf[i] = c;
	  Serial.print(c);
	}
    }
  }
  // Start interrupt tone
  tone(intPin, 1000);
  digitalWrite(BESS_SIG,LOW);
  if(bess_status != RUNNING)
     blink(BESS_NET,bess_status,300);
  else
     digitalWrite(BESS_NET,HIGH);
    
  
}

//======================================
void loop()
//======================================
{
  int x;
  //Serial.println(id1.sig);
  blink(BESS_COM,1,500);
  if (id1.ptrig == 1) 
    {

      temp = analogRead(tempSensor);

      Serial.print("Time ");
      Serial.print(id1.powertime);
      Serial.print("; Puls ");
      Serial.print(id1.ppulses);
      Serial.print("; Power ");
      Serial.print(id1.power);
      Serial.print("; Base ");
      Serial.print(id1.base);
      Serial.print("; Sigmax ");
      Serial.print(id1.sigmax);
      Serial.print("; Temp ");
      Serial.print(temp);
      Serial.println("; ");

//      x = map(id1.sigmax,0,100,0,255);
//      analogWrite(BESS_SIG_VU,x); 
//      delay(1000);
//      x = map(id1.base,0,100,0,255);
//      analogWrite(BESS_SIG_VU,x); 
//      delay(1000);
      if(id1.power < 10000) x = map(id1.power,0,10000,0,255);
      else
        x = 255;
      analogWrite(BESS_SIG_VU,x); 

      client.stop();
      
      if (client.connect(serverName, 80)) 
	{
	  digitalWrite(BESS_NET,HIGH);
	  client.print("GET /data.php?user=");
	  client.print(user);

	  client.print("&time=");
	  client.print(id1.powertime);
              
	  client.print("&puls=");
	  client.print(id1.ppulses);
              
	  client.print("&power=");
	  client.print(id1.power);
              
	  client.print("&base=");
	  client.print(id1.base);
              
	  client.print("&sigmax=");
	  client.print(id1.sigmax);

	  client.print("&temp=");
	  client.print(temp);

	  client.print("&conf=");
	  client.print(user);
              
	  client.println(" HTTP/1.1");
	  client.println("Host: bess.simuino.com");
	  client.println();
	  // Signal number Power level on the optical interface. 1 blink = 100 Watts
	  int temp = round(id1.power/100);
	  if(temp < 100)
	    puls(BESS_COM,temp,100);
	  else
	    blink(BESS_NET,LED_MAX_POWER,300);

	  // Get number of bytes in answer from server
	  nBytes = client.available();
	  Serial.print("Bytes from server: ");
	  Serial.println(nBytes);
	  
	  // Show answer from server
	  if (nBytes > 0) 
	    {
	      for(i=0;i<nBytes;i++)
		{
		  c = client.read();
		  sconf[i] = c;
		  Serial.print(c);
		}
	    }
	  
	} 
      else 
	{
	  digitalWrite(BESS_NET,LOW);
	  blink(BESS_NET,LED_NO_SERVER_CONNECTION,300);
	}
      id1.sigmax = 0;
      id1.ptrig = 0;

    }
  
}
